<template>
  <div class="main" id="main">
    <div class="main-all" id="mainContent" ref="mainAll" :style="isDisabled ? objStyle2 : objStyle">
      <img class="bottom-bg" src="@/assets/image/consult/bottom-bg.png" alt="">
      <div class="talk" id="talkId" :class="isTitle ? 'person-padding' : ''">
        <div class="person-box" v-if="isTitle">
          <div class="person"><img src="@/assets/image/consult/default-avater.png" alt="" /></div>
          <div class="default">
            <div class="title">
              你好，我是人工智能机器人
            </div>
            <div class="question">
              我可以回答你的问题，快来和我聊天吧
            </div>
          </div>
        </div>
        <div class="talk-item" v-for="(item, i) in domList" :key="item.index" :class="`talk-item${i}`">
          <div :id="`item_right${i + 1}`" :class="(i % 2) == 0 ? 'item_right_box' : ''">
            <img v-if="item.type == 1" class="avatar" src="@/assets/image/consult/avatar.png" alt="">
            <div class="item_right" v-if="item.type == 1">
              {{ item.content }}
            </div>
            <div class="left-box" v-if="item.type == 0">
              <div class="person"><img src="@/assets/image/consult/default-avater.png" alt="" /></div>
              <div class="left">
                <div class="loadding-box" v-if="loading && i == domList.length - 1">
                  <div class="dot1"></div>
                  <div class="dot2"></div>
                  <div class="dot3"></div>
                </div>
                <div class="default-content" :class="isDisabled && i == domList.length - 1 ? '' : 'noBorder'"
                  v-html="item.content"></div>
                <div class="doing" v-if="isDisabled && i == domList.length - 1">
                  正在回答中...
                </div>
              </div>
            </div>

          </div>
        </div>
      </div>
    </div>
    <div class="stop-btn" @click="handleStop" v-if="isDisabled">
      <div class="stop-border">
        <div class="stop"></div>
      </div>
      停止回答
    </div>

    <div class="bottom" ref="btmRef">
      <form v-show="!voice">
        <!-- enterkeyhint 将键盘搜索改成发送 -->
        <input type="text" v-model="content" enterkeyhint="send" class="bottom-input" placeholder="请输入您的问题" />
        <img v-if="!voice" @click="cutVoice" width="25" height="25" src="@/assets/image/consult/voice-icon3.png" alt="">
      </form>
      <form v-show="voice" :class="isShowDoing ? 'isHidden' : ''" style="width: 100%;">
        <div v-show="voice" ref="recordButton" class="bottom-input bottom-btn" @touchstart="startPress"
          @touchend="endPress" @touchmove="cancelPress">{{ pressStatus
          }}
        </div>
        <img v-if="voice" @click="cutVoice" width="20" height="20" src="@/assets/image/consult/keyword-icon2.png"
          alt="">
      </form>
      <div v-show="!voice" class="submit_btn" @click="submit">发送</div>
    </div>
    <div class="voice-show" v-if="isShowDoing">
      <div class="voice-top">我在听，请讲话</div>
      <div class="voice-center">松手发送，上滑取消</div>
      <div class="voice-doing">
        <img src="@/assets/image/consult/voice-doing.png" alt="">
      </div>
    </div>
  </div>
</template>

<script>
import { mapActions } from 'vuex'
import { signCallback } from "@/utils/asrauthentication";
import config from "@/utils/config";
import WebAudioSpeechRecognizer from "@/app/webaudiospeechrecognizer";

export default {
  data() {
    return {
      voice: true,//是否语音
      isDisabled: false,
      isStop: false,
      isTitle: false,
      container: null,
      isRefresh: true,
      loading: false,
      fullHeight: document.documentElement.clientHeight,
      content: '',
      // 保存需要的数组
      domList: [],
      query: {
        current: 1,
        size: 1
      },
      objStyle: {
        height: `calc(${this.fullHeight}px - 55px)`
      },
      objStyle2: {
        height: `calc(${this.fullHeight}px - 110px)`
      },
      params: {
        signCallback: signCallback, // 鉴权函数
        // 用户参数
        secretid: config.secretId,
        appid: config.appId, // 实时识别接口参数
        engine_model_type: "16k_zh", // 因为内置WebRecorder采样16k的数据，所以参数
        voice_format: 1,
        hotword_id: "08003a00000000000000000000000000",
        needvad: 1,
        filter_dirty: 1,
        filter_modal: 2,
        filter_punc: 0,
        convert_num_mode: 1,
        word_info: 2,
      },
      isCanStop: false,
      webAudioSpeechRecognizer: null,
      pressStatus: '按下说话',
      pressTimer: null,
      isNoSubmit: true,
      startY: 0,
      isShowDoing: false,
      currentTime: ''
    }
  },
  mounted() {
    this.init();
    // 回显记录数据
    if (JSON.parse(sessionStorage.getItem('messageList')) && JSON.parse(sessionStorage.getItem('messageList')).length > 0) {
      this.domList = JSON.parse(sessionStorage.getItem('messageList'));
      setTimeout(() => {
        let talkItem = document.querySelectorAll('#talkId .talk-item')
        let container = document.querySelector('#mainContent')
        container.scrollTop = container.scrollHeight - talkItem[talkItem.length - 1].offsetHeight
      }, 500)
    } else {
      this.isTitle = true
    }


    this.$nextTick(() => {
      this.objStyle.height = `calc(${this.fullHeight}px - 55px)`
      this.objStyle2.height = `calc(${this.fullHeight}px - 110px)`
      // 是是获取高度
      window.onresize = () => {
        return (() => {
          this.$nextTick(() => {
            window.fullHeight = document.documentElement.clientHeight
            this.fullHeight = window.fullHeight
            this.objStyle.height = `calc(${this.fullHeight}px - 55px)`
            this.objStyle2.height = `calc(${this.fullHeight}px - 110px)`
            this.$nextTick(() => {
              let container = document.querySelector('#mainContent')
              container.scrollTop = container.scrollHeight
            })
          })
        })()
      }
    })

  },
  watch: {},
  methods: {
    ...mapActions(['selectSearchResult', 'getMessage', 'getToken', 'getMessageNew']),

    startPress(event) {
      // 设置一个长按定时器，比如长按 500ms 触发
      event.preventDefault();
      this.startY = event.touches[0].clientY;
      this.pressTimer = setTimeout(() => {
        this.pressStatus = '请讲话';
        this.isNoSubmit = false;
        this.isShowDoing = true
        // 在这里可以执行长按触发的逻辑
        this.start();
      }, 500); // 500ms 为长按触发的时间阈值，可以根据需要调整

      // 在这里可以执行按下时的其他逻辑
      this.pressStatus = '按下';
    },
    endPress() {
      if (!this.isNoSubmit) {
        const that = this
        // 清除定时器，表示松开了
        clearTimeout(this.pressTimer);
        this.pressStatus = '按下说话';
        if (this.isCanStop) {
          this.isNoSubmit = true
          this.end()
          setTimeout(() => {
            that.submit();
          }, 500)
        }
      } else {
        clearTimeout(this.pressTimer);
        this.pressStatus = '按下说话';
        if (this.isCanStop) {
          this.end()
          this.content = ""
        }
        console.log("取消")
      }
      this.isShowDoing = false
      // 在这里可以执行松开时的其他逻辑
    },
    cancelPress(event) {
      const touchY = event.touches[0].clientY;
      const buttonRect = this.$refs.recordButton.getBoundingClientRect();
      const aboveThreshold = touchY < buttonRect.top;
      if (aboveThreshold && (this.startY - touchY > 50)) {
        this.isNoSubmit = true
      }
      // 取消长按事件（比如鼠标离开了区域）

      // 在这里可以执行取消长按时的其他逻辑
    },
    cutVoice() {
      this.voice = !this.voice
    },
    init() {
      this.content = "";
      this.isCanStop = false;
      navigator.mediaDevices.getUserMedia({ audio: true })
    },
    start() {
      let that = this;
      console.log(config)
      this.webAudioSpeechRecognizer = new WebAudioSpeechRecognizer(this.params);
      this.content = "";
      let resultText = "";
      // 开始识别
      this.webAudioSpeechRecognizer.OnRecognitionStart = (res) => {
        console.log("一句话开始", res);
        that.isCanStop = true;
        //识别中
      };
      // 识别变化时
      this.webAudioSpeechRecognizer.OnRecognitionResultChange = (res) => {
        console.log("识别变化时", res);
        that.content = `${resultText}${res.result.voice_text_str}`;
      };
      // 一句话结束
      this.webAudioSpeechRecognizer.OnSentenceEnd = (res) => {
        console.log("一句话结束", res);
        resultText += res.result.voice_text_str;
        that.content = resultText;
      };
      // 识别结束
      this.webAudioSpeechRecognizer.OnRecognitionComplete = (res) => {
        console.log("识别结束", res);
      };
      // 识别错误
      this.webAudioSpeechRecognizer.OnError = (res) => {
        console.log("识别失败", res);
        if (res == '连接未建立或连接已关闭') {
          this.$message.info("松开太快了");
        } else {
          this.$message.error("识别失败");
        }

      };
      this.webAudioSpeechRecognizer.start();
    },
    end() {
      if (this.isCanStop) {
        this.webAudioSpeechRecognizer.stop();
        this.isCanStop = false;
      }
    },
    paperScroll() {
      document.querySelector('.bottom-input').blur()
    },
    handleStop() {
      this.isStop = true
    },
    delayedLoop(iterations, delay, message) {
      console.log(iterations)
      const that = this
      let index = 0;
      function loop() {
        const lastIndex = that.domList.length - 1;
        const updatedContent = message.content.substring(0, index + 1);
        that.domList[lastIndex].content = updatedContent;
        index++;
        setTimeout(() => {
          if (document.querySelector('#talkId .doing')) {
            let talkItem = document.querySelector('#talkId .doing')
            let container = document.querySelector('#mainContent')
            container.scrollTop = container.scrollHeight - talkItem.offsetHeight
          }

        }, 1000)
        if (index < iterations && !that.isStop) {
          setTimeout(loop, delay); // 递归调用，每隔 delay 毫秒执行一次
        } else {
          that.isDisabled = false
          that.isStop = false
        }
      }
      loop(); // 初始调用
    },
    historyClick() {
      console.log("userId", this.$route.query)
      this.$router.push({ path: "/historyList", query: this.$route.query })
    },
    parseEventStreamData(chunk) {
      let data = '';
      const event = chunk.substr(5).trim();
      if (event) {
        try {
          const list = event.trim().split("data:")
          if (list.length > 1) {
            let listStrArr = list.map(element => {
              return JSON.parse(element.trim())
            })
            let str = ""
            listStrArr.forEach(element => {
              element.choices.forEach(element2 => {
                str += element2.delta.content || element2.delta.reasoning_content
              })
            });
            return str;
          } else {
            const newList = JSON.parse(event).choices
            let str = ""
            newList.forEach(element => {
              str += element.delta.reasoning_content || element.delta.content
            });
            console.log(str)
            return str;
          }

        } catch (e) {
          return ""
        }
      } else {
        return ""
      }
    },
    async submit() {
      console.log(this.content)
      if (this.isDisabled) {
        return;
      }

      const that = this
      if (this.content == '') {
        return;
      }
      this.domList.push({
        content: this.content,
        type: 1
      })
      this.loading = true
      this.domList.push({
        content: "",
        type: 0
      })
      setTimeout(() => {
        let talkItem = document.querySelectorAll('#talkId .talk-item')
        let container = document.querySelector('#mainContent')
        container.scrollTop = container.scrollHeight - talkItem[talkItem.length - 1].offsetHeight
      }, 100)
      const response = await fetch('/zs/v2/chat/completions', {
        method: 'POST',
        headers: {
          "Authorization": "Bearer FevbguYaIyGiWSGaBhVx:PPUhJDleYTSPMjDsspaw",  // 请替换XXXXXXXXXX为您的 APIpassword, 获取地址：https://console.xfyun.cn/services/bmx1
          'Content-Type': 'text/event-stream',
          // 其他需要的头部信息
        },
        // 确保数据以流的形式返回
        body: JSON.stringify({
          "model": "x1",
          "user": "user_id",
          "messages": [
            {
              "role": "user",
              "content": this.content
            }
          ],
          // 下面是可选参数
          "stream": true,
        }),
      })
      this.content = "";
      this.isStop = false
      this.loading = false
      this.isDisabled = true
      // 处理流
      console.log(response)
      const reader = response.body.getReader();
      const decoder = new TextDecoder('utf-8');
      let content = ""
      // 定义读取数据的函数
      const readStream = async () => {
        const { done, value } = await reader.read();
        if (done) {
          console.log('Stream finished');
          this.isDisabled = false
          this.isStop = false
          let message = {
            content: content,
            type: 0,
          }
          let messageList = JSON.parse(JSON.stringify(this.domList));
          messageList[messageList.length - 1] = message
          sessionStorage.setItem('messageList', JSON.stringify(messageList))
          return;
        }
        // 将 Uint8Array 转换为字符串
        const chunk = decoder.decode(value, { stream: true });
        content += this.parseEventStreamData(chunk) || ''
        // 继续读取下一个数据块
        if (!this.isStop) {
          readStream();
        } else {
          this.isDisabled = false
          this.isStop = false
        }
        console.log(content)
        const lastIndex = that.domList.length - 1;
        this.domList[lastIndex].content = content
        if (document.querySelector('#talkId .doing')) {
          let talkItem = document.querySelector('#talkId .doing')
          let container = document.querySelector('#mainContent')
          container.scrollTop = container.scrollHeight - talkItem.offsetHeight
        }
      };
      readStream();
      // 指定位置开始
      setTimeout(() => {
        let talkItem = document.querySelector('#talkId .loadding-box')
        console.log(talkItem)
        let container = document.querySelector('#mainContent')
        container.scrollTop = container.scrollHeight - talkItem.offsetHeight
      }, 500)
      // 指定位置结束
    },
    // 去重
    unique(arr) {
      const res = new Map()
      return arr.filter(item => !res.has(item['id']) && res.set(item['id'], 1))
    },
  }
}
</script>

<style lang="scss" scoped>
.bounce-enter-active {
  animation: bounce-in 0.1s linear;
}

.bounce-leave-active {
  animation: bounce-in 0.1s linear;
}

@keyframes bounce-in {
  0% {
    transform: translate(0, -100%);
  }

  100% {
    transform: translate(0, 0);
  }
}

// 去掉input后的删除按钮
.bottom-input::-webkit-search-cancel-button {
  display: none;
}

.bottom-input::placeholder {
  font-size: 14px;
  color: #ccc;
}

.bottom-input:-moz-placeholder {
  /* Mozilla Firefox 4 to 18 */
  color: #ccc;
  font-size: 14px;
}

.bottom-input::-moz-placeholder {
  /* Mozilla Firefox 19+ */
  color: #ccc;
  font-size: 14px;
}

.bottom-btn {
  background: none;
  display: flex;
  justify-content: center;
  padding-left: 60px !important;
  box-sizing: border-box;

}

.bottom-input:-ms-input-placeholder {
  /* Internet Explorer 10+ */
  color: #ccc;
  font-size: 14px;
}

form {
  display: flex;
  align-items: center;
  width: calc(100% - 70px);
  height: 40px;
  background: #FFFFFF;
  border-radius: 8px 8px 8px 8px;
  padding-right: 10px;
  box-sizing: border-box;
}

.main {
  width: 100%;
  height: 100vh;
  // padding-bottom: 58px;
  // height: 400px;
  overflow: hidden;
  background-color: #F7F8F9;

  .bottom {
    position: fixed;
    bottom: 0;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    height: 55px;
    padding: 6px 16px;
    background: #f7f8f9;
    -webkit-user-select: none;
    /* Safari */
    -moz-user-select: none;
    /* Firefox */
    -ms-user-select: none;
    /* Internet Explorer/Edge */
    user-select: none;
    z-index: 2;

    .bottom-input {
      width: calc(100% - 28px);
      background: #ffffff;
      font-size: 14px;
      // color: #CCCCCC;
      color: #1a1a1a;
      padding: 12px 17px;
      margin-right: 8px;
      text-align: left;
      border-radius: 20px;
    }

    .submit_btn {
      width: 58px;
      height: 40px;
      line-height: 42px;
      color: #ffffff;
      font-size: 13px;
      // padding: 10px 17px;
      border-radius: 20px;
      background: #2574fa;
    }
  }

  .main-all {
    position: relative;
    width: 100%;
    // height: calc(100% - 1.7rem);
    // transition: .5s;
    overflow-y: scroll;
    background: linear-gradient(180deg, #2574FA 0%, #CEE2FF 33%, rgba(202, 221, 255, 0) 100%);
    padding-bottom: constant(safe-area-inset-bottom);
    /* 兼容 iOS < 11.2 */
    padding-bottom: env(safe-area-inset-bottom);
    /* 兼容 iOS >= 11.2 */
  }

  .bottom-bg {
    position: fixed;
    left: 0;
    width: 100%;
    top: 30%;
    z-index: 0;
  }

  .work_loading {
    position: fixed;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
  }

  .person-box {
    display: flex;
    padding-left: 12px;
  }

  .person {
    width: 28px;
    height: 28px;
    z-index: 1;
    margin-right: 8px;
    // background: #fff;
    border-radius: 8px;
    box-sizing: border-box;

    img {
      width: 100%;
      height: 100%;

    }
  }

  .default {
    width: 308px;
    background: #FFFFFF;
    border-radius: 14px 14px 14px 14px;
    text-align: left;
    padding: 18px 14px;

    .title {
      font-weight: 600;
      font-size: 18px;
      color: #1A1A1A;
      line-height: 27px;
    }

    .question {
      font-weight: 400;
      font-size: 16px;
      color: #434343;
      line-height: 21px;
      text-align: left;
      margin-top: 10px;
    }
  }

  .talk {
    width: 100%;
    height: 100%;

    .talk-item {
      display: flex;
      flex-wrap: wrap;
      width: 100%;
      overflow: hidden;

      .item_right_box {
        width: 100%;
        position: relative;
        padding-left: 12px;
        display: flex;
        z-index: 1;
        margin-top: 15px;
      }

      .item_right {
        max-width: 308px;
        font-size: 15px;
        color: #1A1A1A;
        padding: 12px 14px;
        background: linear-gradient(to right, #F4FAFF 0%, #C8E1FF 100%);
        border-radius: 14px 14px 14px 14px;
        margin-right: 16px;
        line-height: 22px;
        text-align: left;
        float: right;
      }

      .left-box {
        display: flex;
        margin-top: 15px;
        margin-left: 12px;
      }

      .left {
        position: relative;
        width: 308px;
        // float: left;
        display: flex;
        flex-direction: column;
        text-align: left;
        background: #FFFFFF;
        border-radius: 14px 14px 14px 14px;
        padding: 12px 14px;

        .default-content {
          font-size: 15px;
          color: #151313;
          float: left;
          line-height: 22px;
          padding-bottom: 10px;
          margin-bottom: 10px;
          border-bottom: 1px solid #D8D8D8;
        }

        .noBorder {
          border: none;
          padding-bottom: 0;
          margin-bottom: 0;
        }



        .doing {
          font-weight: 400;
          font-size: 16px;
          line-height: 22px;
          text-align: left;
          color: #999;
        }

        .zb-temp {
          // transition: all 3s linear;
          width: 308px;
          margin-top: 10px;
          padding: 16px 14px;
          float: left;
          background: #ffffff;
          border-radius: 0px 8px 8px 8px;

          .title {
            font-size: 14px;

            font-weight: bold;
            color: #151313;
            margin-bottom: 6px;

            img {
              width: 16px;
              height: 16px;
              float: left;
              margin-top: 1px;
              margin-right: 5px;
            }
          }
        }
      }
    }

  }

  .person-padding {
    padding-top: 22px;
  }
}

.van-loading {
  width: 50px;
  display: inline-block;
  margin-top: 10px;
}

.avatar {
  width: 28px;
  height: 28px;
  margin-right: 10px;
  border-radius: 8px;
}

.avatar-talk {
  width: 28px;
  height: 28px;
  margin-right: 10px;
  background-color: #6A97FF;
  border-radius: 8px;
}

.stop-btn {
  position: fixed;
  bottom: 61px;
  left: 50%;
  transform: translateX(-50%);
  width: 99px;
  height: 29px;
  background: #FFFFFF;
  border-radius: 12px 12px 12px 12px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-weight: 400;
  font-size: 15px;
  font-weight: 600;
  line-height: 29px;
  text-align: center;
  color: #2574FA;

  .stop-border {
    display: flex;
    justify-content: center;
    align-items: center;
    min-width: 14px;
    max-width: 14px;
    height: 14px;
    border: #2574FA 1px solid;
    border-radius: 50%;
    margin-right: 5px;

    .stop {
      min-width: 3px;
      max-width: 3px;
      min-height: 4px;
      max-height: 4px;
      background: #2574FA;
    }
  }
}

.voice-show {
  position: fixed;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 173px;
  background: #fff;
  z-index: 2;
  clip-path: inset(0px 0px 0px 0px round 40% 40% 0px 0px);

  .voice-top {
    font-weight: 400;
    font-size: 16px;
    color: #1A1A1A;
    line-height: 22px;
    text-align: center;
  }


  .voice-center {
    font-weight: 400;
    font-size: 14px;
    color: #999999;
    line-height: 20px;
    margin: 22px 0 9px 0;
  }
}

.isHidden {

  opacity: 0;
}

.voice-doing {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 342px;
  height: 40px;
  background: #ACD1FF;
  border-radius: 30px 30px 30px 30px;

  img {
    width: 256px;
    height: 20px;
  }
}

.loadding-box {
  display: flex;

  .dot1,
  .dot2,
  .dot3 {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-left: 6px;
  }

  .dot1 {
    animation: jump 1.2s -0.4s linear infinite;
    background: #8c8ef7;
  }

  .dot2 {
    animation: jump 1.2s -0.2s linear infinite;
    background: #5e85d1;
  }

  .dot3 {
    animation: jump 1.2s linear infinite;
    background: #2e6de7;
  }

  @keyframes jump {

    0%,
    80%,
    100% {
      transform: scale(0.9);
      opacity: 1.0;
    }

    40% {
      transform: scale(1.1);
      opacity: 0.8;
    }
  }
}

.history {
  position: absolute;
  left: 0px;
  top: 45%;
  width: 34px;
  height: 84px;
  font-size: 14px;
  font-weight: 600;
  padding: 2px 10px;
  color: #0055FF;
  transform: translate(0px, -53%);
  z-index: 9;
  border-radius: 0px 10px 10px 0px;
  background: linear-gradient(360deg, #F4FAFF 0%, #C8E1FF 100%);
  border-image: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(116.00000068545341, 162.00000554323196, 255, 1)) 1 1;
  border: solid 1px;
  border-left: none;
}
</style>
